<?php

	ini_set('memory_limit', '256M');// why?? here.. 

	//include(CMS_HOME_DIR . "lib/pxaccess.inc");
	require("PxPay_Curl.inc.php");
	/**
	 * 	this file is an interface to the standard cart functionality.
	 */
	
	/**
	 * This is the cart wrapper object..
	 *
	 */
	//the fta cart defaults to dps payment..
	class FTACart extends FTAObject {
		
		var $pxaccess;
		var $currency;
		
		var $orderContainer;

		//var $addItemRequiredKeys;
		
		//store the order item here.. 
		var $lastKnownCartPhase;
		
		//
		
		function __construct() {
			parent::__construct();			
			//..$this->currency = "NZD";
			global $db;						
			$this->setCurrency("NZD");
		//	$this->addItemRequiredKeys = array("productId", "quantity");

		}
		
		function setCurrency($currency){
			$this->currency = $currency;
		}
		
		function getCurrency(){
			return $this->currency;
		}
		
		
		function getCurrencySignForCurrency($currency){
			//hack here for currency shit..
			$currencySign = "$";
			switch ($currency){
			
				
				case "GBP":
					$currencySign = "&pound;";
				break;
				
				case "EUR":
					$currencySign = "&euro;";
				break;
			
				case "JPY":
					$currencySign = "&yen;";
				break;
				
				case "NZD":
				case "AUD":
				case "USD":
				default:
					$currencySign = "$";	
				break;
			}
			return $currencySign;			
		}
		
		function getCurrencySign(){
			return $this->getCurrencySignForCurrency($this->getCurrency());
		}
		
		/**
		 * this method returns the main html for the cart.. thing is.. the cart has multiple views and stuff.. so we need to work 
		 * out what is the best thing to show.. this is just the guts of the old cart.php tidied up
		 * and factored in to an object. by doing this, everything is kept nice and tidy and we can reduce
		 * the amout of crap getting in to the global scope.
		 *
		 */
		//function render() {
		function renderCart() {//was called render.. but cart is better
			global $db;
			global $CMS_ORDERCONTAINER_CLASS;
			

			
			///////////
			
			$valid = false; //validateMemberLogin($member,$db);
			
			//create order container.. if we dont have one.. 
			if (is_null($this->orderContainer)) {

				$this->orderContainer = new $CMS_ORDERCONTAINER_CLASS();
				
				//set the default country.. in the request for the take values for key stuff..
				$_REQUEST[ $this->orderContainer->keyForField('country')] = 140;
								
				// auto complete
				$this->orderContainer->takeValueForKey(false,'cartHasLogin');
						
				
			}
			////////// 
			// Pull the dps stuff out of the request.. 
			$this->restoreOrderFromPaymentGateway();
						
			/*
			// if cookie for address is not set then default it to null else we get undefined index error
			if(!isset($_COOKIE['addressFields'])){
				$_COOKIE['addressFields'] = null;
			}
			
			$addressDataFromCookie = extractStringWithKeyFromArray( 'addressFields',$_COOKIE,null);			
						
			//we pull out the data from the cookie and decrypt it.. and insert it.. 
			$canAutocompleteFromCookie = false;
			if (is_string($addressDataFromCookie)){
				$customerDetail = $this->getAddressFromCookie($addressDataFromCookie);
				if(!is_null($customerDetail)) {
					$customerDetail = (array) $customerDetail;		
					$canAutocompleteFromCookie = true;
				}
			}  			
		
			//if we have cookie data we can pre-populate..
			if ($canAutocompleteFromCookie){		
				$this->orderContainer->takeValueForKey( @$customerDetail['firstname'], 'firstName');
				$this->orderContainer->takeValueForKey( @$customerDetail['lastname'], 'lastName');
				$this->orderContainer->takeValueForKey( @$customerDetail['email'], 'email');
				$this->orderContainer->takeValueForKey( @$customerDetail['email'], 'verifyEmail');
				$this->orderContainer->takeValueForKey( @$customerDetail['daytimephone'], 'phone');
				$this->orderContainer->takeValueForKey( @$customerDetail['nighttimephone'], 'phoneNight');
				$this->orderContainer->takeValueForKey( @$customerDetail['mobilephone'], 'mobile');
				$this->orderContainer->takeValueForKey( @$customerDetail['street'], 'street');
				$this->orderContainer->takeValueForKey( @$customerDetail['suburb'], 'suburb');
				$this->orderContainer->takeValueForKey( @$customerDetail['city'], 'city');		
				$this->orderContainer->takeValueForKey( @$customerDetail['country'], 'country');
			}
			*/		
			
			/*
			 populate the order container fields from the request the
			 the order container will in turn populate the fields of its
			 order items.
			*/
			$this->orderContainer->takeValuesFromRequest();
	
			
			# flush out items that are empty.. we dont want them confusing things..
			$this->orderContainer->purgeEmptyOrderItems();
	
			# invoke actions.. on the container..
			# no magical way of passing arguments.. 
			$deleteItemFromContainer = extractStringWithKeyFromArray('deleteItemFromContainer', $_REQUEST, null);
			if( !is_null($deleteItemFromContainer) && strlen($deleteItemFromContainer) == 8){
				$this->orderContainer->removeOrderItemWithId($deleteItemFromContainer,$db);
				$returnUrl = extractStringWithKeyFromArray('returnUrl',$_REQUEST,null);
				if ($returnUrl){
					while (@ob_end_clean());					
					header("Location: " . $returnUrl ,true);
					die();
				}
			}
	
			# we insert a new order item at this point. when?? how.. 
			$createNewOrderItem = extractBooleanWithKeyFromArray(ORDER_CREATE_NEW_ITEM,$_REQUEST, true);
			$orderItem = null;
			/*
			 look for the current order item in the session.. this will set the current/active order item..
			 ie: the one we are currently looking at.. this only really has any use in 
			 wizard type setups where there are muliple steps involed in setting up
			 the order item and populating its fields.
			*/
			if (!$createNewOrderItem) {
				# $orderItem = null;//get the order out of the store
				$orderItemId = $this->orderContainer->valueForKey('currentOrderItemId');
				if (!is_null($orderItemId))
					$orderItem = $this->orderContainer->orderItemWithId( $orderItemId );
			}
		
			# determine the point in the order process that we are upto..
			$orderStep = extractStringWithKeyFromArray(ORDER_STEP_KEY, $_REQUEST, null);
			
			$this->orderContainer->purgeInvalidOrderItems();			
					
					
			$this->orderSwitch($orderStep);
					
			// now the various render stages and what not...
			//;

	//		$_SESSION["FTACart"] = &$this;			
		}


		function orderSwitch($orderStep){
			switch ($orderStep) {
					
					case ORDER_CANCEL:
						$this->cancelOrder();//dont want to include these seperate						
					break;
					
					case ORDER_FINALISE:
						$this->finaliseOrder();			
					break;
			
//					case ORDER_MANUAL_FINALISE:
//						$this->manualFinaliseOrder();
//					break;
					
					case ORDER_ITEM:
						$this->addItemToOrder();
					break;
					
					default:
						$this->displayOrder();
						
					break;
						
					case ORDER_REVIEW:
						$this->reviewOrder();						
					break;
			
					case ORDER_SUBMIT:
						$this->submitOrder();
					break;
					
			}		
		}
								
			
	//	}
		function restoreOrderFromPaymentGateway(){
			
			global $CMS_ORDERCONTAINER_CLASS;
			global $db;	 
			$authInfo = setupPublicUser();

			$this->orderContainer->log($this->orderContainer->id() . " Checking for DPS Result.. .");
			
			$dpsResult = extractStringWithKeyFromArray('result', $_REQUEST, null);
			$pxResponse = null;
			if (!is_null($dpsResult)){
				
				// 
				$this->orderContainer->log($this->orderContainer->id() . " Found DPS Result: " . $dpsResult);
				
				//this is the dps process.. 
				// we need to clean up the existing session here incase we try and update/edit the order..
				//these can cause problems..
				$_SESSION["_CMSKVC"] = null;				
				$this->orderContainer = null;

				$this->orderContainer = new $CMS_ORDERCONTAINER_CLASS();
				$pxaccess = $this->getPxAccess();
				//echo "xxx";
				$pxResponse = $pxaccess->getResponse( $dpsResult );
				$merchantRef = $pxResponse->getMerchantReference() ? $pxResponse->getMerchantReference() : null;
				//print_r($this->orderContainer);
				//echo  "yyy";
				
				
				$this->orderContainer->log($this->orderContainer->id()." Order Id: $merchantRef for DPS Response: " . print_r($pxResponse,true));

				
				$this->orderContainer->log($merchantRef." Return from DPS.. Attempting to Load...");
				
				$this->orderContainer->log("order container id will be fangled from: " . $this->orderContainer->id()." to: " .$merchantRef);	
				$res = $this->orderContainer->load($merchantRef, $authInfo, $db);
				if ($res) {
					

					
					$this->orderContainer->log($this->orderContainer->id()." Return from DPS.. Order with id: " . $merchantRef ." restored");
					
					// since we are in an object, that should be happliy saved back to the session
					// we dont need to do this..
					//$_SESSION[ ORDER_CONTAINER_KEY ] = $this->orderContainer;
					$_SESSION["FTACart"] = &$this;
					
					//HACK HACK HACK.. put these back into the request for the KVC to pull out
					$_REQUEST[ ORDER_CREATE_NEW_ITEM ] = false;	
					$_REQUEST[ ORDER_STEP_KEY ] = ORDER_FINALISE;
				} else {
					$this->orderContainer->log($merchantRef." Return from DPS.. failed to load order with id: " . $merchantRef);					
				}
				$pxaccess = null;
			} else {
				$this->orderContainer->log($this->orderContainer->id() . " No DPS result in request, assume normal cart process");
								
			}
		}
		
		function finaliseOrder(){
			 
			$this->lastKnownCartPhase = ORDER_FINALISE;

			$this->orderContainer->log($this->orderContainer->id() . " Entering Order Finalise:");
			
			global $db;
			
			/*
			 do the ecommerce bit..
			 record the order
			 and process ecommerce results??
			 now we may need to look up the session here.. to finalise things.. as this will also be triggered by
			 the dps..
			*/
			$dpsSuccess = 0;
			$dpsAuthCode = null;
			$dpsMessage = null;
			
			$dpsResult = extractStringWithKeyFromArray('result', $_REQUEST, null);
			
			$pxaccess = $this->getPxAccess();	
			$pxResponse = $pxaccess->getResponse( $dpsResult );
				
			if(!is_null($pxResponse) && $pxResponse->getMerchantReference()){
				$dpsSuccess = $pxResponse->getSuccess();
				$dpsAuthCode = $pxResponse->getAuthCode();
				$dpsMessage = 'DPS '.$pxResponse->getResponseText();
				$pxXml = $pxResponse->toXml();	
			}

			//kvc operation?
			$status = $this->orderContainer->status();
			
			$sendInvoice=false;
			if (true || $status == ORDER_STATUS_PENDING  ) {

				$this->orderContainer->log($this->orderContainer->id() . " Finalising Pending Order");
				
				$this->orderContainer->takeValueForKey( $dpsMessage, 'responseText' );
		  		$this->orderContainer->takeValueForKey( $pxXml, 'pxReceive');
				$this->orderContainer->takeValueForKey( $dpsAuthCode, 'authCode');
			  		
				if ($dpsSuccess == 1)  {
					
					$this->orderContainer->log($this->orderContainer->id() . " DPS success.");
					//$this->orderContainer->takeValueForKey( ORDER_STATUS_AUTH, 'status');
					//This needs to swap depending on the type of transaction
					if($this->getTransactionType() == "Purchase") {
						$this->orderContainer->log($this->orderContainer->id() . " Status set to: " . ORDER_STATUS_ACCEPTED);
						$this->orderContainer->takeValueForKey( ORDER_STATUS_ACCEPTED, 'status');
					} else {
						$this->orderContainer->log($this->orderContainer->id() . " Status set to: " . ORDER_STATUS_AUTH);
						$this->orderContainer->takeValueForKey( ORDER_STATUS_AUTH, 'status');
					}
					
					$sendInvoice=true;
					
					$this->orderContainer->log($this->orderContainer->id() . " Running finalise Process");
					global $FTACartFinaliseProcess;					
					include_once((0 < strlen($FTACartFinaliseProcess)) ? $FTACartFinaliseProcess : "ftaCartFinaliseProcess.php");

					$this->lastKnownCartPhase = ORDER_FINALISE_SUCCESS;

				} else {
					$this->orderContainer->log($this->orderContainer->id() . " DPS declined.");					
					$this->orderContainer->takeValueForKey( ORDER_STATUS_DECLINED, 'status');
					
					$this->lastKnownCartPhase = ORDER_FINALISE_FAIL;
					
				}
										
				$authInfo = setupPublicUser();
				$ut = $authInfo->usertype;
				$authInfo->usertype = 0;
		  		$res = $this->orderContainer->save( $authInfo, $db );
				$authInfo->usertype = $ut;
											
											
			} else {
				$this->orderContainer->log($this->orderContainer->id() . " Order status already updated to: " . $status);
				
			}
			
			$this->orderContainer->log($this->orderContainer->id() . " Displaying Finalise Page"); 
			if ($dpsSuccess == 1) {
				$this->lastKnownCartPhase = ORDER_FINALISE_SUCCESS;							
			} else {
				$this->lastKnownCartPhase = ORDER_FINALISE_FAIL;							
			}
			
			# this page is the page that is displayed .. it is always shown.. and just reflects the order status.
			//include( CMS_ORDER_FINALISE_PAGE );
						
			global $FTACartFinalisePage;						
			include_once((0 < strlen($FTACartFinalisePage)) ? $FTACartFinalisePage : "ftaCartFinalise.php");					
					
		}		

/*
		function manualFinaliseOrder(){
			 
			$this->lastKnownCartPhase = ORDER_FINALISE;
			
			global $db;
			
			global $authInfo;
			/*
			 do the ecommerce bit..
			 record the order
			 and process ecommerce results??
			 now we may need to look up the session here.. to finalise things.. as this will also be triggered by
			 the dps..
			* /
			$dpsSuccess = 1;
			$dpsAuthCode = "00";
			$dpsMessage = "Manual DPS Finalise";
			$pxXml = "zzMANUALzz";

			//kvc operation?
			$status = $this->orderContainer->status();
			
			$sendInvoice=false;
			if (!is_null($authInfo) && $status == ORDER_STATUS_PENDING  ) {

				$this->orderContainer->takeValueForKey( $dpsMessage, 'responseText' );
		  		$this->orderContainer->takeValueForKey( $pxXml, 'pxReceive');
				$this->orderContainer->takeValueForKey( $dpsAuthCode, 'authCode');
			  		
				//if ($dpsSuccess == 1)  {
					
					$this->orderContainer->log($this->orderContainer->id() . " Manual Payment Finalise.");
					$this->orderContainer->takeValueForKey( ORDER_STATUS_AUTH, 'status');
			
					$sendInvoice=true;
					
					global $FTACartFinaliseProcess;					
					include_once((0 < strlen($FTACartFinaliseProcess)) ? $FTACartFinaliseProcess : "ftaCartFinaliseProcess.php");

					$this->lastKnownCartPhase = ORDER_FINALISE_SUCCESS;

				//} else {
				//	$this->orderContainer->log($this->orderContainer->id() . " DPS declined.");					
				//	$this->orderContainer->takeValueForKey( ORDER_STATUS_DECLINED, 'status');
				//	
				//	$this->lastKnownCartPhase = ORDER_FINALISE_FAIL;
				//	
				//}
										
				//$authInfo = setupPublicUser();
				//$ut = $authInfo->usertype;
				//$authInfo->usertype = 0;
				
				//manual approval requires a valid log in to complete.
		  		$res = $this->orderContainer->save( $authInfo, $db );
				//$authInfo->usertype = $ut;
				$this->lastKnownCartPhase = ORDER_FINALISE_SUCCESS;														
			} 
			//if ($dpsSuccess == 1) {
											
			//} else {
			//	$this->lastKnownCartPhase = ORDER_FINALISE_FAIL;							
			//}
			
			# this page is the page that is displayed .. it is always shown.. and just reflects the order status.
			//include( CMS_ORDER_FINALISE_PAGE );
						
			global $FTACartFinalisePage;						
			include_once((0 < strlen($FTACartFinalisePage)) ? $FTACartFinalisePage : "ftaCartFinalise.php");					
					
		}	
*/			
			
		function addItemToOrder(){
			$this->orderContainer->log($this->orderContainer->id() . " adding items to cart");
			
			$this->lastKnownCartPhase = ORDER_ITEM;//tis will get overwritten with ORDER_DISPLAY
			
			$this->orderContainer->takeValueForKey($this->getCurrency(),'currency');
			$this->orderContainer->takeValueForKey($this->getCurrencySign(),'currencySign');
					
			# this creates and adds an order item to the shopping cart...
			
			#1. create it..
				global $CMS_ORDERITEM_CLASS;
				$orderItem = new $CMS_ORDERITEM_CLASS();

			#2. add it to the order container.
				$this->orderContainer->takeValueForKey($orderItem->valueForKey('id'), 'currentOrderItemId');
				$this->orderContainer->setOrderItemWithId($orderItem->valueForKey('id'), $orderItem);
				
				#echo "order container = <pre>";print_r($this->orderContainer);echo "</pre>";
				
			#3. let the order item know who its order container is..
				$orderItem->takeValueForKey($this->orderContainer->valueForKey('id'), "orderContainer" );
				$this->orderContainer->log($this->orderContainer->id() . " has order item: " . $orderItem->id());
				
				/*
				 map the passed in keys to the object..
				 we do this by altering the request variables
				 and calling takeValuesFromRequest.
				*/
			
			#4. get the list of keys that this object expects to read in from the request.
				$initalKeys = $this->getAddItemRequiredKeys();// <----- 
				//$initalKeys = $orderItem->keys();//flatten the keys out into one array....
				
				$containerKeys = $this->orderContainer->keys;
				foreach ($containerKeys as $key => $value) {
					foreach ($containerKeys[$key] as $key2 => $value2) {
						$initalKeys[] = $value2;
					}
				}
				#echo "keys = <pre>";print_r($initialKeys);echo "</pre><br>";
				
			#5. rename the fields so that they can be picked up by takeValuesFromRequest.	
				$id= $orderItem->valueForKey('id');
				foreach ($initalKeys as $key) {
					if (key_exists($key,$_REQUEST)&& !is_null($_REQUEST[$key])){
						$_REQUEST[$id . '_' .$key] = $_REQUEST[$key];
					}
				}
				
			#6. populate fields. and what not..
				# $orderItem->takeValuesFromRequest();
				# pruge empty items here.. just in case
				$this->orderContainer->takeValuesFromRequest();
				$this->orderContainer->purgeEmptyOrderItems();
				
			#7.. we can possibly now fall through to the view cart page.
			# or possibly an order item details page .. TBA

				$this->displayOrder();
		}
				
		function displayOrder() {
			$this->lastKnownCartPhase = ORDER_DISPLAY;
			$this->orderContainer->log($this->orderContainer->id() . " Displaying Order Details Page");
			$this->orderContainer->takeValueForKey($this->getCurrency(),'currency');
			global $FTACartDisplayPage;			
			include_once((0 < strlen($FTACartDisplayPage)) ? $FTACartDisplayPage : "ftaCartDisplay.php");
			//we rip out the invalid..
			$this->orderContainer->takeValueForKey(null,'invalidKeys' );					
			
		}
				
		function submitOrder(){
			
			//these need to be factored into methods for easy replacement.
			$this->lastKnownCartPhase = ORDER_SUBMIT;
			$this->orderContainer->log($this->orderContainer->id() . " Performing Order Submit");
			
			global $db;
			//global $CMS_ORDERCONTAINER_CLASS;
			
			
			$this->orderContainer->takeValueForKey($this->getCurrency(),'currency');	
		
					
			$valid = false;
			$valid = $this->orderContainer->validateForSave();

			if (!$valid) {
				
				$this->orderContainer->log($this->orderContainer->id() . " Order not valid, going back to cart..");
				
				$_SESSION["FTACart"] = &$this;
				
				while (@ob_end_clean());
				header("Location: " . $this->getCartUrl() ,true);
				die();
				
			} else {
				
	
				# if we are here VVVVV data is valid and we have submitted the form/cart ready for payment..
				$this->orderContainer->log($this->orderContainer->id() . " Preparing DPS payload");
				
				$this->orderContainer->takeValueForKey( ORDER_STATUS_PENDING, 'status');
				
				$request = new PxPayRequest();	

//				if($this->orderContainer->valueForKey('country') == 140) {
//fetcht this onces as it needs a trawl of the order items..
				$totalPrice = $this->orderContainer->valueForKey('totalPrice');
				$this->orderContainer->log($this->orderContainer->id() . " Setting transaction amount: " . $totalPrice );
				$request->setAmountInput( $this->orderContainer->valueForKey('totalPrice') ) ;
//				} else {
//					$request->setAmountInput( $this->orderContainer->internationalTotalPrice() ) ;
//				}
				

		  		$request->setTxnData1(  $this->getTransactionMessage() );# whatever you want to appear
				# $request->setTxnData2( 'DPS AUTH' );# whatever you want to appear
				# $request->setTxnData3("data three");# whatever you want to appear
				
				$this->orderContainer->log($this->orderContainer->id() . " Setting transaction Type: " . $this->getTransactionMessage() );
		  		$request->setTxnType($this->getTransactionType());
				
		  		#set the currency..
		  		$this->setCurrency( (strlen($this->getCurrency()) == 3) ? $this->getCurrency() : "NZD");
				$this->orderContainer->log($this->orderContainer->id() . " Setting currency Type: " . $this->getCurrency() );
		  		
				$request->setCurrencyInput($this->getCurrency());
//				$request->setInputCurrency($this->getCurrency());
		  		
		  		$request->setEnableAddBillCard(1);
		  		$request->setBillingId(substr(htmlentities($this->orderContainer->valueForKey('lastName'). " " . $this->orderContainer->valueForKey('firstName')), 0,30));
		  		
		  		$request->setMerchantReference($this->orderContainer->valueForKey('id')); # fill this with your order number
		  		$request->setEmailAddress($this->orderContainer->valueForKey('email'));
				
		  		# set the return urls etc.... this will just be php_self really.. i hope so..		  		
				$request->setUrlFail( PAYMENT_FAIL_URL );
		  		$request->setUrlSuccess( PAYMENT_SUCCESS_URL );			  		

		  		$request->setTxnId($this->orderContainer->id() . "_" . substr( time() . "", -5 ));
		  		
		  		$pxaccess = $this->getPxAccess();
		  		$requestString = $pxaccess->makeRequest($request);
				$this->orderContainer->log($this->orderContainer->id() . " DPS Request: " . print_r($request,true) );
		  		$pxaccess = null;		  		
	  		
		  		$pxXml = $request->toXml();
		  		$this->orderContainer->takeValueForKey( $pxXml, 'pxSend');

				
				$response = new MifMessage($requestString);
					
  				$dpsUrl = $response->get_element_text("URI");
  				$valid = $response->get_attribute("valid");
  				
				if ($valid) {
					$this->orderContainer->log($this->orderContainer->id() . " DPS request response valid, presisting changes" );	
				
		  			$this->orderContainer->takeValueForKey( "Now", 'transactionDate');
	 				$authInfo = setupPublicUser();
					$ut = $authInfo->usertype;
					$authInfo->usertype = 0;
								
				} else {
					$this->orderContainer->log($this->orderContainer->id() . " DPS request response not valid" );
				}

//				
		  		$res = $this->orderContainer->save( $authInfo, $db );
				$authInfo->usertype = $ut;

				if (!$valid || $res->hasErrors) {
					/*
					 display an error message here.. and die..
					 every thing should be valid.. and saved properly.
					 echo "ERROR WITH SAVE FOR SOME REASON..";
					 myPrintR($res);
					
					 we need to set up state and then redirect to a point where we
					 display the error screen in the final step.
					*/
					$_SESSION["FTACart"] = &$this;
					$this->orderContainer->log($this->orderContainer->id()." Failed to save to DB.");
					// include( CMS_ORDER_FINALISE_PAGE );//make a define for this..
					
					while (@ob_end_clean());
					header("Location: " . $this->getConfirmUrl() ,true);					
					die();
					
				} else {
					//dont actually care at this point in time..
					$_SESSION["FTACart"] = &$this;
					
					//$this->orderContainer->log($this->orderContainer->id()." ".$this->orderContainer->toXml());
					$this->orderContainer->log($this->orderContainer->id()." DPS XML: ".$request->toXml());
					$this->orderContainer->log($this->orderContainer->id()." Going to DPS.. Total Order: '". $this->orderContainer->valueForKey('totalPrice') ."'.");
					
					
					while (@ob_end_clean());  
					header("Location: $dpsUrl",true);
					die();
				}
			}				
		}
				
				
		function reviewOrder(){
			
		$this->orderContainer->log($this->orderContainer->id() . " Performing order review:" );

			$this->lastKnownCartPhase = ORDER_REVIEW;
						
			$this->orderContainer->takeValueForKey($this->getCurrency(),'currency');
			//we need to add a check here for the terms agree..
			
			// fucking hack here for the terms radio button..=	
			// radio buttons and checks are the most stupidly annoying thngs know to man.
			$termsAgreeKey = $this->orderContainer->keyForField('termsAgree');
			$termsAgree = extractBooleanWithKeyFromArray($termsAgreeKey, $_REQUEST, null);
			$this->orderContainer->takeValueForKey($termsAgree, 'termsAgree');
										
			$valid = false;
			$valid = $this->orderContainer->validateForSave();
			
		
			if(!$valid){
				$this->orderContainer->log($this->orderContainer->id() . "Order not valid, returning to details page:" );
				$_SESSION["FTACart"] = &$this;
				
				while (@ob_end_clean());
				header("Location: " . $this->getCartUrl(),true);
				die();
			}else{
				$this->orderContainer->log($this->orderContainer->id()." User on review page.");

				global $FTACartReviewPage;	// echo "FTACartReviewPage = $FTACartReviewPage";			
				include_once((0 < strlen($FTACartReviewPage)) ? $FTACartReviewPage : "ftaCartReview.php");
			
			}					
		}
				
		function cancelOrder() {
			
			global $db;

			$this->orderContainer->log($this->orderContainer->id() . " order cancelled" );

			$authInfo = setupPublicUser();
			
			$this->lastKnownCartPhase = ORDER_CANCEL;// we should take this from order step.. but it may not be defined..
			/*
			 cancel the order.. at some point in the future we may want to 
			 add more advanced cleanup  code.. dumping the session for now is 
			 fine..
			*/

			$authInfo = setupPublicUser();
			$ut = $authInfo->usertype;
			$authInfo->usertype = 0;
			$this->orderContainer->cancelOrder($authInfo, $db);
			$authInfo->usertype = $ut;
							

			// $_SESSION["FTACart"] = &$this;
			$_SESSION["FTACart"]->orderContainer->orderItems = array();
			
			
			//
			while (@ob_end_clean());
									
			header("Location: " . $this->getShopUrl() ,true);
			die();					
		}		

		
		
	//
		function getConfirmUrl(){
			global $FTACartConfirmUrl;
			return (0 < strlen($FTACartConfirmUrl)) ? $FTACartConfirmUrl : "/Cart/Confirm/";			
		}
		
		function getCartUrl() {
			global $FTACartUrl;
			return (0 < strlen($FTACartUrl)) ? $FTACartUrl : "/Cart/";
		}

		function getShopUrl() {
			global $FTACartShopUrl;
			return (0 < strlen($FTACartShopUrl)) ? $FTACartShopUrl : "/Cart/";
		}
		
		function getSubmitUrl(){
			global $FTACartSubmitUrl;
			return (0 < strlen($FTACartSubmitUrl)) ? $FTACartSubmitUrl : "/Cart/Submit/";		
		}
			
		

		
		function getTransactionMessage() {
			global $FTACartTransactionMessage;
			return (0 < strlen($FTACartTransactionMessage)) ? $FTACartTransactionMessage : "Purchase";				
		}
		
		function getFinaliseUrl(){
			global $FTACartFinaliseUrl;
			return (0 < strlen($FTACartFinaliseUrl)) ? $FTACartFinaliseUrl : "/Cart/Finalise/";				
		}


		function getTransactionType(){
			global $FTACartTransactionType;
			return (0 < strlen($FTACartTransactionType)) ? $FTACartTransactionType : "Purchase";	
		}

		//in next version.. this hsould be pushed into the order item 
		function getAddItemRequiredKeys() {
			global $FTAAddItemRequiredKeys;
			return (0 < count($FTAAddItemRequiredKeys)) ? $FTAAddItemRequiredKeys : array("productId", "quantity");	
							
			
		}
		
		function renderInlineCartContents(){}
		
		
		
		function getAddressFromCookie($cookieData){

			if(!isset($cookieData) || is_null($cookieData))
				return null;
		
	
			//echo "COOKIE DATA: " . $cookieData;
			/*=================== ENCRYPT STUFF===================*/
			$cookieData = pack('H*', $cookieData);    
			$td = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_ECB, '');
			mcrypt_generic_init($td, CMS_CRYPT_KEY, CMS_CRYPT_IV);
			$cookieData = mdecrypt_generic($td, $cookieData);
			mcrypt_generic_deinit($td);
			mcrypt_module_close($td);
			
			/*=================== ENCRYPT STUFF======================*/
			$cookieData = utf8_decode($cookieData);
			
			//$cookieForAddress = stripslashes($cookieData);//why????
			$cd =  json_decode(trim($cookieData));
			return $cd;
		}



		function setCookieFromAddress(&$orderContainer){

			$o = new stdClass();
			
			$o->firstname = $orderContainer->valueForKey( 'firstName');
			$o->lastname = $orderContainer->valueForKey( 'lastName');
			$o->email = $orderContainer->valueForKey( 'email');
			$o->verifyemail = $orderContainer->valueForKey( 'verifyEmail');
			$o->daytimephone = $orderContainer->valueForKey( 'phone');
			$o->phonenight = $orderContainer->valueForKey( 'phoneNight');
			$o->mobilephone = $orderContainer->valueForKey( 'mobile');
			$o->street = $orderContainer->valueForKey( 'street');
			$o->suburb = $orderContainer->valueForKey( 'suburb');
			$o->city = $orderContainer->valueForKey( 'city');		
			$o->country = $orderContainer->valueForKey( 'country');
					
			$cookieStuff = json_encode( $o );
			$cookieStuff = utf8_encode($cookieStuff);
	
		    $td = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_ECB, '');		
		    mcrypt_generic_init($td, CMS_CRYPT_KEY, CMS_CRYPT_IV);
		    $cookieStuff = mcrypt_generic($td, $cookieStuff);
		    mcrypt_generic_deinit($td);
		    mcrypt_module_close($td);    
		    $cookieStuff = bin2hex($cookieStuff);
    
			setcookie("addressFields", $cookieStuff, strtotime("next year"),"/");	//domain, path, expire...
		}
		
		
		/**
		 * this is a helper method that returns an instance of a pxaccess object for perparing data
		 * and what not for handing off to dps..
		 *
		 * @return pxaccess
		 */
		function &getPxAccess() {
		//	if (is_null($this->pxaccess)) 
		//		$this->pxaccess = new PxAccess(PX_ACCESS_URL, PX_ACCESS_USERID, PX_ACCESS_KEY, PX_ACCESS_MAC_KEY);
		//	return $this->pxaccess;
		
			if (is_null($this->pxaccess)){
  				$this->pxaccess = new PxPay_Curl( PX_ACCESS_URL, PX_ACCESS_USERID, PX_ACCESS_KEY . PX_ACCESS_MAC_KEY );
			}
			return $this->pxaccess;
		}			
			
		function renderCartGoogleAnalytics(){
			//get the last known order step.. and choose the right order step..
			// to customise the results..
			global $fta_;
			global $FTAGoogleAnalyticsCode;//assume this is always set
			
			if ( 
			 (!array_key_exists('analyticsEmbedded',$fta_) || is_null($FTAGoogleAnalyticsCode) || !$fta_->analyticsEmbedded)		
			){
				$fta_->analyticsEmbedded = true; 
				
				switch($this->lastKnownCartPhase){

					case ORDER_SUBMIT:
						$cartUrl = "/Cart/Submit/";							
					break;
					
					case ORDER_REVIEW:
						$cartUrl = "/Cart/Review/";						
					break;

					case ORDER_CANCEL:
						$cartUrl = "/Cart/Cancel/";
					break;
	
					case ORDER_FINALISE:
						$cartUrl = "/Cart/Finalise/";
					break;
					
					case ORDER_FINALISE_SUCCESS:
						$cartUrl = "/Cart/Finalise/Success/";
					break;
					
					case ORDER_FINALISE_FAIL:
						$cartUrl = "/Cart/Finalise/Fail/";
					break;
						
					case ORDER_ITEM:
					case ORDER_ITEM_EDIT:
					case ORDER_CREATE_NEW_ITEM:
					case ORDER_DISPLAY:
					default:
						$cartUrl = '/Cart/';// the default/view item url;
				}

				
?>
<!--  cart analytics  -->
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
 try {
var pageTracker = _gat._getTracker("<?=  $FTAGoogleAnalyticsCode ?>");
pageTracker._trackPageview("<?= $cartUrl ?>");
<?php 
	//here we can serialise out the cart for full e-commerce reporting..
	//if ()
	if (ORDER_FINALISE_SUCCESS == $this->lastKnownCartPhase) {
/*
 *   pageTracker._addTrans(
      "1234", // order ID - required
      "Womens Apparel", // affiliation or store name
      "11.99", // total - required
      "1.29", // tax
      "15.00", // shipping
      "San Jose", // city
      "California", // state or province
      "USA" // country
    );
 */		
?>		
pageTracker._addTrans("<?= $this->orderContainer->valueForKey('id'); ?>","","<? printf("%01.2f",  $this->orderContainer->valueForKey('totalPrice'));?>","","<? printf("%01.2f",  $this->orderContainer->valueForKey('shippingPrice'));?>","<? echo ($this->orderContainer->valueForKey('city'));?>","<? echo ($this->orderContainer->valueForKey('state'));?>","<? echo ($this->orderContainer->valueForKey('countryAsISOCode'));?>");					

<?php 
	// add items here
	$orderItems = $this->orderContainer->orderItems();//not sure why i am not using the kvc here.. hrrm..
	foreach($orderItems as $oi){
/*
    pageTracker._addItem(
      "1234", // order ID - necessary to associate item with transaction
      "DD44", // SKU/code - required
      "T-Shirt", // product name - necessary to associate revenue with product
      "Olive Medium", // category or variation
      "11.99", // unit price - required
      "1" // quantity - required
   );
 */
?>
pageTracker._addItem("<?= $this->orderContainer->valueForKey('id'); ?>", "<?= $oi->valueForKey('productId'); ?>", "<?= $oi->valueForKey('productName'); ?>", "", "<?= printf("%01.2f",  $oi->valueForKey('price')); ?>", "<?= $oi->valueForKey('quantity'); ?>" );
<?php 
	}
?>
	pageTracker._trackTrans();
<?php 
	}		
?>
 } catch(err) {}
</script>			
<?php 	
			}		
		}
		
	}
	
	
	
	
	
	/**
	 * This function is used to embed the cart/shopping process into a page.. 
	 *
	 */
	
	function fta_getCart(){
		ob_start();
		$ftaCart = &fta_getCartObject();
		$ftaCart->renderCart();	
		return ob_get_clean();
	}
	
	/**
	 * This function gets the contents of the cart and prints an inline list.. 
	 *
	 */
	
	function fta_getInlineCartContents() {
		ob_start();
		$ftaCart = &fta_getCartObject();
		$ftaCart->renderInlineCarContents();			
		return ob_get_clean();
	}
	
	function fta_sendCartHeaders(){
		header("Cache-Control: no-cache, must-revalidate",true); // HTTP/1.1
		header("Expires: Sat, 26 Jul 1997 05:00:00 GMT", true); // Date in the past
		header("Pragma: no-cache",true);		
	}
	
	
	function fta_cartGoogleAnalytics(){
		//works out the cart stage we should be at.. based on request details etc and corrects the standard analytics code.. 
		ob_start();
		$ftaCart = &fta_getCartObject();
		$ftaCart->renderCartGoogleAnalytics();		
		return ob_get_clean();		
	}
	
	function fta_cartCleanup(){
		// we work out the last known step and clen up.. this should always be the last item to run in a cart page..
		// we dont dont this in the object.. as its bad.. and will get confusing..
		$ftaCart = &fta_getCartObject();
		if (ORDER_FINALISE_SUCCESS == $ftaCart->lastKnownCartPhase ) {
			//successful orders can goes here.. 
			// here we just remove all of the objects.. and hope that they go away..
			$ftaCart = null;
			unset($_SESSION['FTACart']);
			
			
			//
		} else if (ORDER_FINALISE_FAIL == $ftaCart->lastKnownCartPhase ) {
			//fail orders here.  // not sure if we need to clean up or not .. just leave for now.. 
		} else {
			//the rest of the states.. 	//nothing happens here.. 
		}
		
	}
	/**
	 * This creates and returns the fta cart object .. the cart objects are per session.. not per prequest.. 
	 *
	 */

	//WTF: This has the wrong name.. 
	function &fta_getCartObject(){//wrong name.. damnit! // TOOOOO late 
		
		global $FTACartClass;
				
		//FIXME: cant have side effects on the global variable.
		//this is a simple registration hook to ensure that the correct subclass files are loaded
		//before sessions
		global $FTACartClass;
		if(!is_null($FTACartClass)){
		} else {
			$FTACartClass = "FTACart";
		}
		
		if(!isset($_SESSION)) {
			session_start();
		}
		
		$o = extractObjectWithKeyOfClassFromArray('FTACart',$FTACartClass,$_SESSION,null );
		if (is_null($o)){		
			$o = new $FTACartClass();			
		}
		
		//we need to remember to stick things back in the session if we fuck about with them
		$_SESSION['FTACart'] = &$o;	
				
		return $o;	
		
		
	}
	
	
	
	//again.. this needs to be labelled global as we are included inside a magical place.
	//this set of stuff needs a session.. and if we call stuff that wants to start a session
	//and content has already be sent.. we break.. so we do this when the class / module is loaded..
	
//	global $fta_;	
//	$fta_->startSession();